import 'dart:convert';

import 'package:dartkit/dartkit.dart';
import 'package:http/http.dart' as http;

part 'args.dart';
part 'model.dart';

class SmsKit {
  /// 将验证码与输入的码进行比较，无论是sms缺失、过期、不匹配等原因都会抛出错误
  /// sms可以为null，就是说比如某个用户下查不到sms验证码，那么也可以传入，会正常报错
  static void validate(Sms? sms, String codeInput) {
    // 1. 尚未发送过验证码
    if (sms == null) throw Bug("尚未发送验证码，请先发送");
    // 2. 验证码已过期
    if (sms.hasExpired) throw Bug("验证码已过期");
    // 3. 校验错误
    if (codeInput != sms.code) throw Bug("验证码校验不匹配");
  }

  /// 警告：目前这个方法是我调试了很久得出来的成功路径，由于云片的API代码写得极烂、不可调试，因此我建议不要修改这里
  /// 就算自己的app已经全面用dio了，这里需要使用http库也随他去吧
  ///
  /// 向某个特定的手机号发送验证码
  /// 目前使用云片服务商，由于DartKit目前已在网络公开，因此apiKey等隐私信息需要自行在项目中输入
  static Future<void> sendWithYunpian(String phone, String code) async {
    if (phone.length != 11) throw BugDev("手机号长度必须为11位");
    // 使用云片的编码格式（x-www-form-urlencoded）向云片发送请求
    // 并获得回复
    final response = await http.post(
      Uri.parse("https://sms.yunpian.com/v2/sms/tpl_single_send.json"),
      headers: {
        'Content-Type': "application/x-www-form-urlencoded; charset=utf-8"
      },
      body:
          "apikey=${argSms.value.apiKey}&tpl_id=${argSms.value.templateId}&tpl_value=%23code%23=$code&mobile=$phone",
    );

    /// 有两种失败的可能性，一种是非200返回码，另一种是200返回码但是code不是0（也算失败）
    /// 对于任意情况，都需要使用Bug来进行错误处理

    // 由于此处使用http库而非dio库，因此不成功的信息需要自行判断
    if (response.statusCode == 200) {
      // 有时候即使收到200回复，也有可能是发送失败的，需要自行甄别
      // 如果短信失败，则显示具体的原因
      final result = jsonDecode(response.body);
      // 在云片的规范中，code为0则是发送成功，否则为失败
      final smsFail = result['code'] != 0;
      if (smsFail) throw Bug("短信发送失败：${result["detail"]}");
    } else {
      // 在开发阶段，显示具体的原因
      print(response.reasonPhrase);

      /// body["code"]是短信的错误码
      /// body["http_status_code"]是http服务器的错误码
      /// body["msg"]是说明
      /// body["detail"]是详细说明
      print(response.body);
      final map = jsonDecode(response.body);
      throw Bug('运营商拒绝发送短信: ${map["detail"]}');
    }
  }
}
